// -------------- 手写 bind ----------------
if (!Function.prototype.myBind) {
    Function.prototype.myBind = function (thisArg, ...presetArgs) {
      const targetFn = this;                      // 1. 记下原函数（调用 myBind 的函数）
      if (typeof targetFn !== 'function') {       // 2. 兜底校验，跟原生保持一致
        throw new TypeError('Bind must be called on a function');
      }
  
      // 3. 返回的新函数（可 new、可普通调用）
      function boundFn(...laterArgs) {
        // 3-a 检测是否通过 new 调用（new 绑定优先级最高）
        const isNewCall = this instanceof boundFn;
        const context = isNewCall ? this : Object(thisArg); // 非 new 时把 thisArg 转对象
  
        // 3-b 执行原函数，合并两次传入的参数
        return targetFn.apply(context, [...presetArgs, ...laterArgs]);
      }
  
      // 4. 维护原型链：new 出来的实例要能继承原函数原型上的方法
      if (targetFn.prototype) {
        boundFn.prototype = Object.create(targetFn.prototype);
      }
  
      // 5. 补全一些内置属性（可选，面试加分）
      Object.defineProperty(boundFn, 'length', {
        value: Math.max(0, targetFn.length - presetArgs.length),
        writable: false,
        configurable: false
      });
      Object.defineProperty(boundFn, 'name', {
        value: `bound ${targetFn.name || 'anonymous'}`,
        configurable: true
      });
  
      return boundFn;   // 6. 把绑定后的函数交出去
    };
  }




// -------------- 手写 bind 渡一版本-------------------
Function.prototype.NewBind=function(context,...args){
    if(typeof this !== 'function'){ // 确保是一个函数调用这个newBind(),否则抛出一个错误
        throw new Error('type error')
    }
        let fn = this  //谁调用这个NewBind就指向谁,this指向调用NewBind的函数
    return function(...laterArgs){ //最终会返回一个函数,该函数可以接收剩余参数

        if(new.target){//如果当前函数是通过new调用的话
            return new fn(...args,...laterArgs)  //fn就是调用NewBind的函数,保持new的优先级最高的规则
        }
        return  fn.apply(context,[...args,...laterArgs])//也可以使用call,需要将返回结果return
    }
}  

function test(a,b,c,d){
    console.log(a,b,c,d)
    console.log(this)
    return a+b+c+d
}

const newFn =  test.NewBind({x:1},2,3)
// console.log(newFn(4,5))
// new 操作符做了这些事情：
// 1. 创建一个新的空对象
// 2. 将这个空对象的 __proto__ 指向构造函数的 prototype
// 3. 将构造函数的 this 绑定到这个新对象
// 4. 执行构造函数
// 5. 如果构造函数返回对象，则返回该对象；否则返回新创建的对象
const f = new newFn(4,5)  
//通过new关键字的返回结果是空字符
//new newFn(4,5) 创建了一个新对象
// 但是 newFn 内部调用 fn.apply(context, ...) 时，强制将 this 绑定到了 {x:1}
// 由于返回值不是对象，new 操作符就返回了最初创建的空对象
console.log(f)

const newFn2 = test.bind({x:1},2,3)
const f2 = new newFn2(4,5)
console.log(f2)